using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UniversalAdmin.Application.Dto;
using UniversalAdmin.Application.Commands;
using UniversalAdmin.Domain.Entities.App;
using UniversalAdmin.Domain.Repositories;
using UniversalAdmin.Shared.Enums;
using Microsoft.EntityFrameworkCore;
using UniversalAdmin.Infrastructure.Data.Contexts;

namespace UniversalAdmin.Application.Services
{
    public class AppMenuService : IAppMenuService
    {
        private readonly IRepository<AppMenu> _menuRepository;
        private readonly IRepository<AppRole> _roleRepository;
        private readonly AdminDbContext _db;

        public AppMenuService(IRepository<AppMenu> menuRepository, IRepository<AppRole> roleRepository, AdminDbContext db)
        {
            _menuRepository = menuRepository;
            _roleRepository = roleRepository;
            _db = db;
        }

        public async Task<ApiResult<PagedResult<MenuDto>>> GetPagedAsync(PagedQuery query)
        {
            var q = _db.AppMenus.Where(m => !m.IsDelete);
            if (!string.IsNullOrWhiteSpace(query.Search))
                q = q.Where(m => m.MenuName.Contains(query.Search) || (m.Path ?? "").Contains(query.Search) || (m.Icon ?? "").Contains(query.Search));
            var total = await q.CountAsync();
            var items = await q.OrderByDescending(m => m.SortOrder)
                .ThenBy(m => m.Id)
                .Skip((query.Page - 1) * query.Size)
                .Take(query.Size)
                .Select(m => new MenuDto
                {
                    Id = m.Id,
                    MenuName = m.MenuName,
                    Path = m.Path,
                    Icon = m.Icon,
                    ParentId = m.ParentId,
                    SortOrder = m.SortOrder,
                    IsActive = m.IsActive
                })
                .ToListAsync();
            return ApiResult<PagedResult<MenuDto>>.Success((int)ApiStatusCode.SUCCESS, "操作成功", new PagedResult<MenuDto>(items, total, query.Page, query.Size));
        }

        public async Task<ApiResult<IEnumerable<MenuDto>>> GetAllAsync(string? search = null)
        {
            var q = _db.AppMenus.Where(m => !m.IsDelete);
            if (!string.IsNullOrWhiteSpace(search))
                q = q.Where(m => m.MenuName.Contains(search) || (m.Path ?? "").Contains(search) || (m.Icon ?? "").Contains(search));
            var items = await q.OrderByDescending(m => m.SortOrder)
                .ThenBy(m => m.Id)
                .Select(m => new MenuDto
                {
                    Id = m.Id,
                    MenuName = m.MenuName,
                    Path = m.Path,
                    Icon = m.Icon,
                    ParentId = m.ParentId,
                    SortOrder = m.SortOrder,
                    IsActive = m.IsActive
                })
                .ToListAsync();
            return ApiResult<IEnumerable<MenuDto>>.Success((int)ApiStatusCode.SUCCESS, "操作成功", items.AsEnumerable());
        }

        public async Task<ApiResult<MenuDto>> GetByIdAsync(Guid id)
        {
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null || menu.IsDelete)
                return ApiResult<MenuDto>.Failed("菜单不存在", (int)ApiStatusCode.NOT_FOUND);
            var dto = new MenuDto
            {
                Id = menu.Id,
                MenuName = menu.MenuName,
                Path = menu.Path,
                Icon = menu.Icon,
                ParentId = menu.ParentId,
                SortOrder = menu.SortOrder,
                IsActive = menu.IsActive
            };
            return ApiResult<MenuDto>.Success((int)ApiStatusCode.SUCCESS, "操作成功", dto);
        }

        public async Task<ApiResult<MenuDto>> CreateAsync(CreateMenuDto dto)
        {
            if (_menuRepository.Table.Any(m => m.MenuName == dto.MenuName && !m.IsDelete))
                return ApiResult<MenuDto>.Failed("菜单名已存在", (int)ApiStatusCode.CONFLICT);

            var menu = new AppMenu
            {
                Id = Guid.NewGuid(),
                MenuName = dto.MenuName,
                Path = dto.Path,
                Icon = dto.Icon,
                ParentId = dto.ParentId,
                SortOrder = dto.SortOrder,
                IsDelete = false
            };
            await _menuRepository.CreatedAsync(menu);
            var result = new MenuDto
            {
                Id = menu.Id,
                MenuName = menu.MenuName,
                Path = menu.Path,
                Icon = menu.Icon,
                ParentId = menu.ParentId,
                SortOrder = menu.SortOrder,
                IsActive = menu.IsActive
            };
            return ApiResult<MenuDto>.Success((int)ApiStatusCode.SUCCESS, "创建成功", result);
        }

        public async Task<ApiResult<MenuDto>> UpdateAsync(Guid id, UpdateMenuDto dto)
        {
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null || menu.IsDelete)
                return ApiResult<MenuDto>.Failed("菜单不存在", (int)ApiStatusCode.NOT_FOUND);

            if (_menuRepository.Table.Any(m => m.MenuName == dto.MenuName && m.Id != id && !m.IsDelete))
                return ApiResult<MenuDto>.Failed("菜单名已存在", (int)ApiStatusCode.CONFLICT);

            menu.MenuName = dto.MenuName;
            menu.Path = dto.Path;
            menu.Icon = dto.Icon;
            menu.ParentId = dto.ParentId;
            menu.SortOrder = dto.SortOrder;
            await _menuRepository.UpdateAsync(menu);

            var result = new MenuDto
            {
                Id = menu.Id,
                MenuName = menu.MenuName,
                Path = menu.Path,
                Icon = menu.Icon,
                ParentId = menu.ParentId,
                SortOrder = menu.SortOrder,
                IsActive = menu.IsActive
            };
            return ApiResult<MenuDto>.Success((int)ApiStatusCode.SUCCESS, "修改成功", result);
        }

        public async Task<ApiResult> DeleteAsync(Guid id)
        {
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null)
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "菜单不存在");
            if (menu.IsDelete)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "菜单已被删除，不能重复删除");

            menu.IsDelete = true;
            await _menuRepository.UpdateAsync(menu);
            return ApiResult.Success((int)ApiStatusCode.SUCCESS, "删除成功");
        }

        public async Task<ApiResult> EnableAsync(Guid id)
        {
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null)
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "菜单不存在");
            if (menu.IsDelete)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "菜单已被删除，无法启用");
            if (menu.IsActive)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "菜单已是启用状态");
            menu.IsActive = true;
            await _menuRepository.UpdateAsync(menu);
            return ApiResult.Success((int)ApiStatusCode.SUCCESS, "启用成功");
        }

        public async Task<ApiResult> DisableAsync(Guid id)
        {
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null)
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "菜单不存在");
            if (menu.IsDelete)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "菜单已被删除，无法禁用");
            if (!menu.IsActive)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "菜单已是禁用状态");
            menu.IsActive = false;
            await _menuRepository.UpdateAsync(menu);
            return ApiResult.Success((int)ApiStatusCode.SUCCESS, "禁用成功");
        }

        public async Task<ApiResult> AssignRolesAsync(AssignMenuRolesDto dto)
        {
            var menu = await _db.AppMenus.Include(m => m.Roles).FirstOrDefaultAsync(m => m.Id == dto.MenuId);
            if (menu == null || menu.IsDelete)
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "菜单不存在");
            var distinctIds = dto.RoleIds.Distinct().ToList();
            var roles = _db.AppRoles.Where(r => distinctIds.Contains(r.Id) && !r.IsDelete).ToList();
            if (roles.Count != distinctIds.Count)
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "部分角色不存在");
            // 覆盖式分配
            menu.Roles.Clear();
            await _db.SaveChangesAsync(); // 先清空
            foreach (var role in roles)
                menu.Roles.Add(role);
            await _db.SaveChangesAsync(); // 再分配
            return ApiResult.Success((int)ApiStatusCode.SUCCESS, "分配角色成功");
        }
    }
} 